/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package colas;

import Distribuciones.Exponencial;
import ec.util.MersenneTwisterFast;

/**
 *
 * @author gabula
 */
public class Procesos {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        MersenneTwisterFast prng = new MersenneTwisterFast(12343);
        //Distribuciones de tiempo entre llegadas, y del tiempo de servicio
        Exponencial ell = new Exponencial(30);
        Exponencial s1 = new Exponencial(40);

        //Las listas de servidores
        java.util.ArrayList<Servidor> sn1 = new java.util.ArrayList<Servidor>();

        //Adicionan servidores
        sn1.add(new Servidor(s1, 0.0, 1));
       

        //Se crea la lista de eventos
        double Tll = 0, Tll1 = 0;
        java.util.ArrayList<Evento> fel = new java.util.ArrayList<Evento>();
        fel.add(new Evento(0.0, 'i', 0, 0));

        //Numero de clientes
        int n = 100000;
        double sumaW = 0.0;

        int cliente_llegan = 0;
        int clientes_salen = 0;
        int sumaC = 0;
        int clienteSistema = 0;

        double sumaWS = 0D;
        double suma2W = 0D;
        double sumaS = 0D;
        double suma2S = 0D;
        double sumaWC = 0D;
        double suma2WC = 0D;
        
        
        for (int i = 1; i <= n; i++) {
            double tllegada = ell.generar(prng.nextDouble()) * 60;
            Tll = Tll1 + tllegada;
            Cliente cn = new Cliente(Tll);
            java.util.Collections.sort(sn1);
            int servidor = 0;
            //Se revisa si el cliente tiene o no no que esperar
            //y a que servidor pasa a ser atendido
            if (Tll > sn1.get(sn1.size() - 1).getTiempo_desocupa()) {
                servidor = (int) Math.floor(sn1.size() * Math.random());
                cn.setS(sn1.get(servidor).tiempoServicio() * 60);
                cn.setW(0.0);
                cn.setTS();
                sn1.get(servidor).setTiempo_desocupa(cn.getTS());
                sn1.get(servidor).setTotal_ocupado(cn.getS());
            } else if (Tll < sn1.get(0).getTiempo_desocupa()) {
                servidor = 0;
                cn.setS(sn1.get(servidor).tiempoServicio() * 60);
                cn.setW(sn1.get(servidor).getTiempo_desocupa() - Tll);
                cn.setTS();
                sn1.get(servidor).setTiempo_desocupa(cn.getTS());
                sn1.get(servidor).setTotal_ocupado(cn.getS());
            } else {
                int ser_libres = 0;
                int ser_ocupados = 0;
                for (int j = 0; j < sn1.size(); j++) {
                    double tiempo_des = sn1.get(j).getTiempo_desocupa();
                    if (tiempo_des < Tll) {
                        ser_libres++;
                    } else {
                        ser_ocupados++;
                    }
                }
                servidor = ((int) Math.floor(Math.random() * ser_libres));
                cn.setS(sn1.get(servidor).tiempoServicio() * 60);
                cn.setW(0.0);
                cn.setTS();
                sn1.get(servidor).setTiempo_desocupa(cn.getTS());
                sn1.get(servidor).setTotal_ocupado(cn.getS());
            }
            sumaS += cn.getS();
            suma2S += cn.getS()*cn.getS();
            sumaWS += cn.getS()*cn.getW();
            sumaW += cn.getW();
            suma2W += cn.getW()*cn.getW();
            

            double controlW = cn.getW() + (-0.02887659397540961)*(cn.getS() - 1.5015466016044614);
            sumaWC += controlW;
            suma2WC += controlW*controlW;
            double tsalida = cn.getTS();

            fel.add(new Evento(Tll, 'l', i, (sn1.get(servidor).getN_servidor())));
            fel.add(new Evento(tsalida, 's', i, (sn1.get(servidor).getN_servidor())));
            java.util.Collections.sort(fel);

            while (fel.get(0).getTiempo() <= Tll) {
                Evento evento_proximo = fel.get(0);
                switch (evento_proximo.getTipo_evento()) {
                    case 'i': {
                        fel.remove(0);
                        break;
                    }
                    case 'l': {
                        System.out.println("Llegada Cliente: " + evento_proximo.getCliente() + " al servidor " + evento_proximo.getServidor() + " " + evento_proximo.getTiempo());
                        fel.remove(0);
                        cliente_llegan++;
                        clienteSistema = cliente_llegan - clientes_salen - 1;
                        sumaC += clienteSistema;
                        break;
                    }
                    case 's': {
                        System.out.println("Salida Cliente: " + evento_proximo.getCliente() + " del servidor " + evento_proximo.getServidor() + " " + evento_proximo.getTiempo());
                        fel.remove(0);
                        clientes_salen++;
                        //clienteSistema = cliente_llegan - clientes_salen + 1;
                        //sumaC += clienteSistema;
                        break;
                    }
                }
            }
            //fel.add(new Evento(0.0, 'i', 0, 0));
            Tll1 = Tll;
        }
        while (fel.size() > 0) {
            Evento evento_proximo = fel.get(0);
            switch (evento_proximo.getTipo_evento()) {
                case 'i': {
                    fel.remove(0);
                    break;
                }
                case 'l': {
                    System.out.println("Llegada Cliente: " + evento_proximo.getCliente() + " al servidor " + evento_proximo.getServidor() + " " + evento_proximo.getTiempo());
                    fel.remove(0);
                    cliente_llegan++;
                    clienteSistema = cliente_llegan - clientes_salen - 1;
                    sumaC += clienteSistema;
                    break;
                }
                case 's': {
                    System.out.println("Salida Cliente: " + evento_proximo.getCliente() + " del servidor " + evento_proximo.getServidor() + " " + evento_proximo.getTiempo());
                    fel.remove(0);
                    clientes_salen++;
                    //clienteSistema = cliente_llegan - clientes_salen + 1;
                    //sumaC += clienteSistema;
                    break;
                }
            }
        }
        
        double mediaS = sumaS/n;
        double mediaW = sumaW/n;
        double mediaWC = sumaWC/n;
        double covarianzaXY = (sumaWS - mediaS*sumaW)/(n-1)*1D;
        double varS = (suma2S- mediaS*mediaS*n)/(n-1)*1D;
        double varW = (suma2W- mediaW*mediaW*n)/(n-1)*1D;
        double varWC = (suma2WC- mediaWC*mediaWC*n)/(n-1)*1D;

        System.out.println("media S: "+mediaS);
        System.out.println("varianza S: " + varS);
        System.out.println("covarianza de S y W: " + covarianzaXY);
        System.out.println("media W: " + mediaW);
        System.out.println("varianza W: " + varW);
        System.out.println("media WC: " + mediaWC);
        System.out.println("varianza WC: " + varWC);
        double a = (-1 * covarianzaXY)/varS;
        System.out.println("a: " + a);
        for (int i = 0; i < sn1.size(); i++) {
            System.out.println("El servidor " + sn1.get(i).getN_servidor() + " estuvo ocupado el " + (sn1.get(i).getTotal_ocupado() / sn1.get(i).getTiempo_desocupa()));
        }
        System.out.println("Tiempo medio de espera " + sumaW / (n * 1d));
        System.out.println("Numero promedio de clientes " + (sumaC * 1d) / (n * 1d));
    }
}
